//! Calculates the set of unique abbreviations for a given set of words.
//! (Borrowed from Ruby's Abbrev.)
//!

use std::collections::{HashMap, HashSet};

/// Given a list of strings, returns a map of unique abbreviations for members of 
/// the given list. 
///
/// # Example
///
/// ```
/// let strings = vec!["car", "cot", "dog"];
/// let result = gecliht::abbrevs(&strings);
///
/// assert_eq!(result["ca"], "car");
/// assert_eq!(result["car"], "car");
/// assert_eq!(result["co"], "cot");
/// assert_eq!(result["d"], "dog");
/// assert_eq!(result["dog"], "dog");
/// ```
/// 
pub fn abbrevs<'a> (strings : &'a [&str]) -> HashMap<String, &'a str> {
    return abbrevs_from_prefix (strings, "");
}

/// Given a list of strings, returns a map of unique abbreviations for members of 
/// the given list. Each abbreviation must begin with the given prefix.
///
/// # Example
///
/// ```
/// let strings = vec!["car", "cot", "dog"];
/// let result = gecliht::abbrevs_from_prefix(&strings, "c");
///
/// assert_eq!(result["ca"], "car");
/// assert_eq!(result["car"], "car");
/// assert_eq!(result["co"], "cot");
/// assert!(!result.contains_key("d"));
/// ```
///
pub fn abbrevs_from_prefix<'a> (strings : &'a [&str], prefix : &str) -> HashMap<String, &'a str>  {
    let mut result = HashMap::new ();
    let mut seen = HashSet::new ();

    for string in strings.iter () {
        for idx in 1..=string.len () {
            let new_abbrev = string.get(0..idx).unwrap ();
            if new_abbrev.starts_with(prefix) { // abbreviations must match the prefix
                if seen.contains(new_abbrev) {
                    // delete abbrev as not unique
                    result.remove_entry (new_abbrev);
                } else {
                    // abbrev not seen before, so add to result
                    result.insert (String::from(new_abbrev), string.clone());
                    seen.insert (new_abbrev);
                }
            }
        }
    }

    return result;
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn empty () {
        let strings = vec![];
        let result = abbrevs(&strings);

        assert!(result.is_empty());
    }

    #[test]
    fn empty_prefix () {
        let strings = vec![];
        let result = abbrevs_from_prefix(&strings, "abc");

        assert!(result.is_empty());
    }

    #[test]
    fn one_word () {
        let strings = vec!["abcd"];
        let result = abbrevs(&strings);

        assert_eq!(4, result.len ());
        for abbrev in vec!["a", "ab", "abc", "abcd"] {
            assert_eq!(result.contains_key(abbrev), true);
            assert_eq!(&"abcd", result.get(abbrev).unwrap ());
        }
    }

    #[test]
    fn one_word_prefix () {
        let strings = vec!["abcd"];
        let result = abbrevs_from_prefix(&strings, "ab");

        assert_eq!(3, result.len ());
        for abbrev in vec!["ab", "abc", "abcd"] {
            assert_eq!(result.contains_key(abbrev), true);
            assert_eq!(&"abcd", result.get(abbrev).unwrap ());
        }
    }

    #[test]
    fn two_words () {
        let strings = vec!["car", "cat"];
        let result = abbrevs(&strings);

        assert_eq!(2, result.len ());
        assert_eq!(result.contains_key("car"), true);
        assert_eq!(result.get("car").unwrap (), &"car");
        assert_eq!(result.contains_key("cat"), true);
        assert_eq!(result.get("cat").unwrap (), &"cat");
    }

    #[test]
    fn two_words_more () {
        let strings = vec!["car", "cone"];
        let result = abbrevs(&strings);

        assert_eq!(5, result.len ());
        assert_eq!(result.contains_key("ca"), true);
        assert_eq!(result.get("ca").unwrap (), &"car");
        assert_eq!(result.contains_key("car"), true);
        assert_eq!(result.get("car").unwrap (), &"car");
        assert_eq!(result.contains_key("co"), true);
        assert_eq!(result.get("co").unwrap (), &"cone");
        assert_eq!(result.contains_key("con"), true);
        assert_eq!(result.get("con").unwrap (), &"cone");
        assert_eq!(result.contains_key("cone"), true);
        assert_eq!(result.get("cone").unwrap (), &"cone");
    }

    #[test]
    fn words_with_prefix () {
        let strings = vec!["car", "cat", "dog"];
        let result = abbrevs_from_prefix(&strings, "c");

        assert_eq!(2, result.len ());
        assert_eq!(result.contains_key("car"), true);
        assert_eq!(result.get("car").unwrap (), &"car");
        assert_eq!(result.contains_key("cat"), true);
        assert_eq!(result.get("cat").unwrap (), &"cat");
    }

    #[test]
    fn words_with_prefix2 () {
        let strings = vec!["car", "cat", "dog"];
        let result = abbrevs_from_prefix(&strings, "d");

        assert_eq!(3, result.len ());
        assert_eq!(result.contains_key("d"), true);
        assert_eq!(result.get("d").unwrap (), &"dog");
        assert_eq!(result.contains_key("do"), true);
        assert_eq!(result.get("do").unwrap (), &"dog");
        assert_eq!(result.contains_key("dog"), true);
        assert_eq!(result.get("dog").unwrap (), &"dog");
    }

}
